package com.iversonx.proxy.example_1.controller.v3;

import com.iversonx.proxy.example_1.domain.RequestInfo;
import com.iversonx.proxy.example_1.service.MetricsCollector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 *
 **/
@Component
public class UserControllerProxyV2 {
    private final Logger logger = LoggerFactory.getLogger(UserControllerProxyV2.class);
    private final MetricsCollector metricsCollector;
    public UserControllerProxyV2(MetricsCollector metricsCollector) {
        this.metricsCollector = metricsCollector;
    }
    
    public <T> T createProxy(T proxiedObject) {
        Class<?>[] interfaces = proxiedObject.getClass().getInterfaces();
        DynamicProxyHandler handler = new DynamicProxyHandler(proxiedObject);
        ClassLoader classLoader = proxiedObject.getClass().getClassLoader();
        return (T)Proxy.newProxyInstance(classLoader, interfaces, handler);
    }
    
    private class DynamicProxyHandler implements InvocationHandler {
        private final Object proxiedObject;
        public DynamicProxyHandler(Object proxiedObject) {
            this.proxiedObject = proxiedObject;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            logger.info("Enter dynamic proxy");
            long start = System.currentTimeMillis();
            Object result = method.invoke(proxiedObject, args);
            long end = System.currentTimeMillis();
            String methodName = method.getName();
            recordRequest(methodName, start, end);
            logger.info("Exit dynamic proxy");
            return result;
        }
    }
    private void recordRequest(String type, long start, long end) {
        RequestInfo requestInfo = new RequestInfo();
        requestInfo.setType(type);
        requestInfo.setStartTime(start);
        requestInfo.setResponseTime(end);
        metricsCollector.recordRequest(requestInfo);
    }
    
}
